<?php
namespace App;

use Exception;

class AliyunSmsSdk
{
    private $conf = [];

    public function __construct($conf = [])
    {
        $this->conf = config('sms.aliyun');
        $this->setConf($conf);
    }

    public function setConf($conf)
    {
        $this->conf = array_merge($this->conf, $conf);
        return true;
    }

    /**
     * 单一发短信接口 (接口版本：2017-05-25)
     *
     * @param           $mobile
     * @param           $params
     * @param null      $template
     * @param null      $sign
     *
     * @return bool
     * @throws Exception
     */
    public function singleSendSms($mobile, $params, $template = null, $sign = null)
    {
        $data = [
            'Action'       => 'SendSms',
            'SignName'     => empty($sign) ? $this->conf['signName'] : $sign,
            'TemplateCode' => empty($template) ? $this->conf['templateCode'] : $template,
            'PhoneNumbers'       => $mobile,
            'TemplateParam'  => json_encode($params),
            'RegionId' => 'cn-hangzhou'
        ];
        if (empty($data['SignName']) || empty($data['TemplateCode'])) {
            return false;
        }
        $tmp              = $this->mergePublicParams($data);
        $tmp['Signature'] = $this->sign('POST', $tmp);
        $ch               = curl_init();
        $options          = [
            CURLOPT_URL            => 'https://' . $this->conf['host'] . '/',
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query($tmp),
            CURLOPT_HEADER         => false,
            CURLOPT_RETURNTRANSFER => true,
        ];
        curl_setopt_array($ch, $options);
        $r    = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $res = json_decode($r, true);
        if ($code == 200 && $res['Code'] == 'OK') {
            return true;
        }
        throw new Exception($r, $code);
    }

    /**
     * 合并“公共请求参数”
     *
     * @link https://help.aliyun.com/document_detail/44362.html
     */
    private function mergePublicParams($data)
    {
        $default = [
            'Format'           => $this->conf['format'],
            'Version'          => $this->conf['version'],
            'SignatureVersion' => $this->conf['signatureVersion'],
            'SignatureMethod'  => $this->conf['signatureMethod'],
            'AccessKeyId'      => $this->conf['accessKeyId'],
            'Timestamp'        => gmDate("Y-m-d\TH:i:s\Z"),
            'SignatureNonce'   => uniqid('', true),
        ];
        return array_merge($default, $data);
    }

    /**
     * 签名
     *
     * @link https://help.aliyun.com/document_detail/44363.html
     */
    private function sign($httpMethod, $data)
    {
        ksort($data);
        $q = http_build_query($data);
        return base64_encode(hash_hmac('sha1', $httpMethod . '&%2F&' . rawurlencode($q),
            $this->conf['accessKeySecret'] . '&', true));
    }
}